home *** CD-ROM | disk | FTP | other *** search
- Subject: v24i023: GNU Diff, version 1.15, Part08/08
- Newsgroups: comp.sources.unix
- Approved: rsalz@uunet.UU.NET
- X-Checksum-Snefru: fe64831c 7eba4177 12fe286e cdb0fff2
-
- Submitted-by: Paul Eggert <eggert@twinsun.com>
- Posting-number: Volume 24, Issue 23
- Archive-name: gnudiff1.15/part08
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 8 (of 8)."
- # Contents: diff3.c
- # Wrapped by eggert@ata on Mon Jan 7 11:25:32 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'diff3.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'diff3.c'\"
- else
- echo shar: Extracting \"'diff3.c'\" \(46642 characters\)
- sed "s/^X//" >'diff3.c' <<'END_OF_FILE'
- X/* Three-way file comparison program (diff3) for Project GNU
- X Copyright (C) 1988, 1989 Free Software Foundation, Inc.
- X
- X This program is free software; you can redistribute it and/or modify
- X it under the terms of the GNU General Public License as published by
- X the Free Software Foundation; either version 1, or (at your option)
- X any later version.
- X
- X This program is distributed in the hope that it will be useful,
- X but WITHOUT ANY WARRANTY; without even the implied warranty of
- X MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- X GNU General Public License for more details.
- X
- X You should have received a copy of the GNU General Public License
- X along with this program; if not, write to the Free Software
- X Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
- X
- X
- X/* Written by Randy Smith */
- X
- X#ifdef __STDC__
- X#define VOID void
- X#else
- X#define VOID char
- X#endif
- X
- X/*
- X * Include files.
- X */
- X#include <stdio.h>
- X#include <ctype.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X
- X#ifdef USG
- X#include <fcntl.h>
- X
- X/* Define needed BSD functions in terms of sysV library. */
- X
- X#define bcmp(s1,s2,n) memcmp((s1),(s2),(n))
- X#define bzero(s,n) memset((s),0,(n))
- X
- X#ifndef XENIX
- X#define dup2(f,t) (close(t),fcntl((f),F_DUPFD,(t)))
- X#endif
- X
- X#define vfork fork
- X
- X#else /* not USG */
- X#include <sys/wait.h>
- X#endif /* not USG */
- X
- X#ifndef WEXITSTATUS
- X#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
- X#undef WIFEXITED /* Avoid 4.3BSD incompatibility with Posix. */
- X#endif
- X#ifndef WIFEXITED
- X#define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
- X#endif
- X
- X#ifdef sparc
- X/* vfork clobbers registers on the Sparc, so don't use it. */
- X#define vfork fork
- X#endif
- X
- X/*
- X * Internal data structures and macros for the diff3 program; includes
- X * data structures for both diff3 diffs and normal diffs.
- X */
- X
- X/*
- X * Different files within a diff
- X */
- X#define FILE0 0
- X#define FILE1 1
- X#define FILE2 2
- X
- X/*
- X * Three way diffs are build out of two two-way diffs; the file which
- X * the two two-way diffs share is:
- X */
- X#define FILEC FILE0
- X
- X/* The ranges are indexed by */
- X#define START 0
- X#define END 1
- X
- Xenum diff_type {
- X ERROR, /* Should not be used */
- X ADD, /* Two way diff add */
- X CHANGE, /* Two way diff change */
- X DELETE, /* Two way diff delete */
- X DIFF_ALL, /* All three are different */
- X DIFF_1ST, /* Only the first is different */
- X DIFF_2ND, /* Only the second */
- X DIFF_3RD /* Only the third */
- X};
- X
- X/* Two-way diff */
- Xstruct diff_block {
- X int ranges[2][2]; /* Ranges are inclusive */
- X char **lines[2]; /* The actual lines (may contain nulls) */
- X int *lengths[2]; /* Line lengths (including newlines, if any) */
- X struct diff_block *next;
- X};
- X
- X/* Three-way diff */
- X
- Xstruct diff3_block {
- X enum diff_type correspond; /* Type of diff */
- X int ranges[3][2]; /* Ranges are inclusive */
- X char **lines[3]; /* The actual lines (may contain nulls) */
- X int *lengths[3]; /* Line lengths (including newlines, if any) */
- X struct diff3_block *next;
- X};
- X
- X/*
- X * Access the ranges on a diff block.
- X */
- X#define D_LOWLINE(diff, filenum) \
- X ((diff)->ranges[filenum][START])
- X#define D_HIGHLINE(diff, filenum) \
- X ((diff)->ranges[filenum][END])
- X#define D_NUMLINES(diff, filenum) \
- X (D_HIGHLINE((diff), (filenum)) - D_LOWLINE((diff), (filenum)) + 1)
- X
- X/*
- X * Access the line numbers in a file in a diff by relative line
- X * numbers (i.e. line number within the diff itself). Note that these
- X * are lvalues and can be used for assignment.
- X */
- X#define D_RELNUM(diff, filenum, linenum) \
- X (*((diff)->lines[filenum] + linenum))
- X#define D_RELLEN(diff, filenum, linenum) \
- X (*((diff)->lengths[filenum] + linenum))
- X
- X/*
- X * And get at them directly, when that should be necessary.
- X */
- X#define D_LINEARRAY(diff, filenum) \
- X ((diff)->lines[filenum])
- X#define D_LENARRAY(diff, filenum) \
- X ((diff)->lengths[filenum])
- X
- X/*
- X * Next block.
- X */
- X#define D_NEXT(diff) ((diff)->next)
- X
- X/*
- X * Access the type of a diff3 block.
- X */
- X#define D3_TYPE(diff) ((diff)->correspond)
- X
- X/*
- X * Line mappings based on diffs. The first maps off the top of the
- X * diff, the second off of the bottom.
- X */
- X#define D_HIGH_MAPLINE(diff, fromfile, tofile, lineno) \
- X ((lineno) \
- X - D_HIGHLINE ((diff), (fromfile)) \
- X + D_HIGHLINE ((diff), (tofile)))
- X
- X#define D_LOW_MAPLINE(diff, fromfile, tofile, lineno) \
- X ((lineno) \
- X - D_LOWLINE ((diff), (fromfile)) \
- X + D_LOWLINE ((diff), (tofile)))
- X
- X/*
- X * General memory allocation function.
- X */
- X#define ALLOCATE(number, type) \
- X (type *) xmalloc ((number) * sizeof (type))
- X
- X/*
- X * Options variables for flags set on command line.
- X *
- X * ALWAYS_TEXT: Treat all files as text files; never treat as binary.
- X *
- X * EDSCRIPT: Write out an ed script instead of the standard diff3 format.
- X *
- X * FLAGGING: Indicates that in the case of overlapping diffs (type
- X * DIFF_ALL), the lines which would normally be deleted from file 1
- X * should be preserved with a special flagging mechanism.
- X *
- X * DONT_WRITE_OVERLAP: 1 if information for overlapping diffs should
- X * not be output.
- X *
- X * DONT_WRITE_SIMPLE: 1 if information for non-overlapping diffs
- X * should not be output.
- X *
- X * FINALWRITE: 1 if a :wq should be included at the end of the script
- X * to write out the file being edited.
- X *
- X * MERGE: output a merged file.
- X */
- Xint always_text;
- Xint edscript;
- Xint flagging;
- Xint dont_write_overlap;
- Xint dont_write_simple;
- Xint finalwrite;
- Xint merge;
- X
- Xextern int optind;
- X
- Xchar *argv0;
- X
- X/*
- X * Forward function declarations.
- X */
- Xstruct diff_block *process_diff ();
- Xstruct diff3_block *make_3way_diff ();
- Xvoid output_diff3 ();
- Xint output_diff3_edscript ();
- Xint output_diff3_merge ();
- Xvoid usage ();
- X
- Xstruct diff3_block *using_to_diff3_block ();
- Xint copy_stringlist ();
- Xstruct diff3_block *create_diff3_block ();
- Xint compare_line_list ();
- X
- Xchar *read_diff ();
- Xenum diff_type process_diff_control ();
- Xchar *scan_diff_line ();
- X
- Xstruct diff3_block *reverse_diff3_blocklist ();
- X
- XVOID *xmalloc ();
- XVOID *xrealloc ();
- X
- Xchar diff_program[] = DIFF_PROGRAM;
- X
- X/*
- X * Main program. Calls diff twice on two pairs of input files,
- X * combines the two diffs, and outputs them.
- X */
- Xmain (argc, argv)
- X int argc;
- X char **argv;
- X{
- X int c, i;
- X int mapping[3];
- X int rev_mapping[3];
- X int incompat;
- X int overlaps_found;
- X struct diff_block *thread1, *thread2;
- X struct diff3_block *diff;
- X int tag_count = 0;
- X /* Element 0 is for file 0, element 1 is for file 2. */
- X char *tag_strings[2];
- X extern char *optarg;
- X char *commonname;
- X struct stat statb;
- X
- X incompat = 0;
- X tag_strings[0] = tag_strings[1] = 0;
- X
- X argv0 = argv[0];
- X
- X while ((c = getopt (argc, argv, "aeimx3EXL:")) != EOF)
- X {
- X switch (c)
- X {
- X case 'a':
- X always_text = 1;
- X break;
- X case 'x':
- X dont_write_simple = 1;
- X incompat++;
- X break;
- X case '3':
- X dont_write_overlap = 1;
- X incompat++;
- X break;
- X case 'i':
- X finalwrite = 1;
- X break;
- X case 'm':
- X merge = 1;
- X break;
- X case 'X':
- X dont_write_simple = 1;
- X /* Falls through */
- X case 'E':
- X flagging = 1;
- X /* Falls through */
- X case 'e':
- X incompat++;
- X break;
- X case 'L':
- X /* Handle one or two -L arguments. */
- X if (tag_count < 2)
- X {
- X tag_strings[tag_count++] = optarg;
- X break;
- X }
- X /* Falls through */
- X case '?':
- X default:
- X usage ();
- X /* NOTREACHED */
- X }
- X }
- X
- X edscript = incompat & ~merge; /* -eExX3 without -m implies ed script. */
- X flagging |= ~incompat & merge; /* -m without -eExX3 implies -E. */
- X
- X if (incompat > 1 /* Ensure at most one of -eExX3. */
- X || finalwrite & (~incompat | merge)
- X /* -i needs one of -eExX3; -i -m would rewrite input file. */
- X || tag_count && ! flagging /* -L requires one of -EX. */
- X || argc - optind != 3)
- X usage ();
- X
- X if (tag_strings[0] == 0)
- X tag_strings[0] = argv[optind];
- X if (tag_strings[1] == 0)
- X tag_strings[1] = argv[optind + 2];
- X
- X if (*argv[optind] == '-' && *(argv[optind] + 1) == '\0')
- X {
- X /* Sigh. We've got standard input as the first arg. We can't */
- X /* call diff twice on stdin */
- X if (! strcmp (argv[optind + 1], "-") || ! strcmp (argv[optind + 2], "-"))
- X fatal ("`-' specified for more than one input file");
- X mapping[0] = 1;
- X mapping[1] = 2;
- X mapping[2] = 0;
- X rev_mapping[1] = 0;
- X rev_mapping[2] = 1;
- X rev_mapping[0] = 2;
- X }
- X else
- X {
- X /* Normal, what you'd expect */
- X mapping[0] = 0;
- X mapping[1] = 1;
- X mapping[2] = 2;
- X rev_mapping[0] = 0;
- X rev_mapping[1] = 1;
- X rev_mapping[2] = 2;
- X }
- X
- X for (i = 0; i < 3; i++)
- X if (argv[optind + i][0] != '-' || argv[optind + i][1] != '\0')
- X if (stat (argv[optind + i], &statb) < 0)
- X perror_with_exit (argv[optind + i]);
- X else if ((statb.st_mode & S_IFMT) == S_IFDIR)
- X {
- X fprintf (stderr, "%s: %s: Is a directory\n", argv0,
- X argv[optind + i]);
- X exit (2);
- X }
- X
- X
- X commonname = argv[optind + rev_mapping[0]];
- X thread1 = process_diff (commonname, argv[optind + rev_mapping[1]]);
- X thread2 = process_diff (commonname, argv[optind + rev_mapping[2]]);
- X diff = make_3way_diff (thread1, thread2);
- X if (edscript)
- X overlaps_found
- X = output_diff3_edscript (stdout, diff, mapping, rev_mapping,
- X tag_strings[0], argv[optind+1], tag_strings[1]);
- X else if (merge)
- X {
- X if (! freopen (commonname, "r", stdin))
- X perror_with_exit (commonname);
- X overlaps_found
- X = output_diff3_merge (stdin, stdout, diff, mapping, rev_mapping,
- X tag_strings[0], argv[optind+1], tag_strings[1]);
- X if (ferror (stdin))
- X fatal ("read error");
- X }
- X else
- X {
- X output_diff3 (stdout, diff, mapping, rev_mapping);
- X overlaps_found = 0;
- X }
- X
- X if (ferror (stdout) || fflush (stdout) != 0)
- X fatal ("write error");
- X exit (overlaps_found);
- X}
- X
- X/*
- X * Explain, patiently and kindly, how to use this program. Then exit.
- X */
- Xvoid
- Xusage ()
- X{
- X fprintf (stderr, "Usage:\t%s [-exEX3 [-i | -m] [-L label1 -L label3]] file1 file2 file3\n",
- X argv0);
- X fprintf (stderr, "\tOnly one of [exEX3] allowed\n");
- X exit (2);
- X}
- X
- X/*
- X * Routines that combine the two diffs together into one. The
- X * algorithm used follows:
- X *
- X * File0 is shared in common between the two diffs.
- X * Diff01 is the diff between 0 and 1.
- X * Diff02 is the diff between 0 and 2.
- X *
- X * 1) Find the range for the first block in File0.
- X * a) Take the lowest of the two ranges (in File0) in the two
- X * current blocks (one from each diff) as being the low
- X * water mark. Assign the upper end of this block as
- X * being the high water mark and move the current block up
- X * one. Mark the block just moved over as to be used.
- X * b) Check the next block in the diff that the high water
- X * mark is *not* from.
- X *
- X * *If* the high water mark is above
- X * the low end of the range in that block,
- X *
- X * mark that block as to be used and move the current
- X * block up. Set the high water mark to the max of
- X * the high end of this block and the current. Repeat b.
- X *
- X * 2) Find the corresponding ranges in Files1 (from the blocks
- X * in diff01; line per line outside of diffs) and in File2.
- X * Create a diff3_block, reserving space as indicated by the ranges.
- X *
- X * 3) Copy all of the pointers for file0 in. At least for now,
- X * do bcmp's between corresponding strings in the two diffs.
- X *
- X * 4) Copy all of the pointers for file1 and 2 in. Get what you
- X * need from file0 (when there isn't a diff block, it's
- X * identical to file0 within the range between diff blocks).
- X *
- X * 5) If the diff blocks you used came from only one of the two
- X * strings of diffs, then that file (i.e. the one other than
- X * file 0 in that diff) is the odd person out. If you used
- X * diff blocks from both sets, check to see if files 1 and 2 match:
- X *
- X * Same number of lines? If so, do a set of bcmp's (if a
- X * bcmp matches; copy the pointer over; it'll be easier later
- X * if you have to do any compares). If they match, 1 & 2 are
- X * the same. If not, all three different.
- X *
- X * Then you do it again, until you run out of blocks.
- X *
- X */
- X
- X/*
- X * This routine makes a three way diff (chain of diff3_block's) from two
- X * two way diffs (chains of diff_block's). It is assumed that each of
- X * the two diffs passed are off of the same file (i.e. that each of the
- X * diffs were made "from" the same file). The three way diff pointer
- X * returned will have numbering 0--the common file, 1--the other file
- X * in diff1, and 2--the other file in diff2.
- X */
- Xstruct diff3_block *
- Xmake_3way_diff (thread1, thread2)
- X struct diff_block *thread1, *thread2;
- X{
- X/*
- X * This routine works on the two diffs passed to it as threads.
- X * Thread number 0 is diff1, thread number 1 is diff2. The USING
- X * array is set to the base of the list of blocks to be used to
- X * construct each block of the three way diff; if no blocks from a
- X * particular thread are to be used, that element of the using array
- X * is set to 0. The elements LAST_USING array are set to the last
- X * elements on each of the using lists.
- X *
- X * The HIGH_WATER_MARK is set to the highest line number in File 0
- X * described in any of the diffs in either of the USING lists. The
- X * HIGH_WATER_THREAD names the thread. Similarly the BASE_WATER_MARK
- X * and BASE_WATER_THREAD describe the lowest line number in File 0
- X * described in any of the diffs in either of the USING lists. The
- X * HIGH_WATER_DIFF is the diff from which the HIGH_WATER_MARK was
- X * taken.
- X *
- X * The HIGH_WATER_DIFF should always be equal to LAST_USING
- X * [HIGH_WATER_THREAD]. The OTHER_DIFF is the next diff to check for
- X * higher water, and should always be equal to
- X * CURRENT[HIGH_WATER_THREAD ^ 0x1]. The OTHER_THREAD is the thread
- X * in which the OTHER_DIFF is, and hence should always be equal to
- X * HIGH_WATER_THREAD ^ 0x1.
- X *
- X * The variable LAST_DIFF is kept set to the last diff block produced
- X * by this routine, for line correspondence purposes between that diff
- X * and the one currently being worked on. It is initialized to
- X * ZERO_DIFF before any blocks have been created.
- X */
- X
- X struct diff_block
- X *using[2],
- X *last_using[2],
- X *current[2];
- X
- X int
- X high_water_mark;
- X
- X int
- X high_water_thread,
- X base_water_thread,
- X other_thread;
- X
- X struct diff_block
- X *high_water_diff,
- X *other_diff;
- X
- X struct diff3_block
- X *result,
- X *tmpblock,
- X *result_last,
- X *last_diff;
- X
- X static struct diff3_block zero_diff = {
- X ERROR,
- X { {0, 0}, {0, 0}, {0, 0} },
- X { (char **) 0, (char **) 0, (char **) 0 },
- X { (int *) 0, (int *) 0, (int *) 0 },
- X (struct diff3_block *) 0
- X };
- X
- X /* Initialization */
- X result = result_last = (struct diff3_block *) 0;
- X current[0] = thread1; current[1] = thread2;
- X last_diff = &zero_diff;
- X
- X /* Sniff up the threads until we reach the end */
- X
- X while (current[0] || current[1])
- X {
- X using[0] = using[1] = last_using[0] = last_using[1] =
- X (struct diff_block *) 0;
- X
- X /* Setup low and high water threads, diffs, and marks. */
- X if (!current[0])
- X base_water_thread = 1;
- X else if (!current[1])
- X base_water_thread = 0;
- X else
- X base_water_thread =
- X (D_LOWLINE (current[0], FILE0) > D_LOWLINE (current[1], FILE0));
- X
- X high_water_thread = base_water_thread;
- X
- X high_water_diff = current[high_water_thread];
- X
- X#if 0
- X /* low and high waters start off same diff */
- X base_water_mark = D_LOWLINE (high_water_diff, FILE0);
- X#endif
- X
- X high_water_mark = D_HIGHLINE (high_water_diff, FILE0);
- X
- X /* Make the diff you just got info from into the using class */
- X using[high_water_thread]
- X = last_using[high_water_thread]
- X = high_water_diff;
- X current[high_water_thread] = high_water_diff->next;
- X last_using[high_water_thread]->next
- X = (struct diff_block *) 0;
- X
- X /* And mark the other diff */
- X other_thread = high_water_thread ^ 0x1;
- X other_diff = current[other_thread];
- X
- X /* Shuffle up the ladder, checking the other diff to see if it
- X needs to be incorporated */
- X while (other_diff
- X && D_LOWLINE (other_diff, FILE0) <= high_water_mark + 1)
- X {
- X
- X /* Incorporate this diff into the using list. Note that
- X this doesn't take it off the current list */
- X if (using[other_thread])
- X last_using[other_thread]->next = other_diff;
- X else
- X using[other_thread] = other_diff;
- X last_using[other_thread] = other_diff;
- X
- X /* Take it off the current list. Note that this following
- X code assumes that other_diff enters it equal to
- X current[high_water_thread ^ 0x1] */
- X current[other_thread]
- X = current[other_thread]->next;
- X other_diff->next
- X = (struct diff_block *) 0;
- X
- X /* Set the high_water stuff
- X If this comparison is equal, then this is the last pass
- X through this loop; since diff blocks within a given
- X thread cannot overlap, the high_water_mark will be
- X *below* the range_start of either of the next diffs. */
- X
- X if (high_water_mark < D_HIGHLINE (other_diff, FILE0))
- X {
- X high_water_thread ^= 1;
- X high_water_diff = other_diff;
- X high_water_mark = D_HIGHLINE (other_diff, FILE0);
- X }
- X
- X /* Set the other diff */
- X other_thread = high_water_thread ^ 0x1;
- X other_diff = current[other_thread];
- X }
- X
- X /* The using lists contain a list of all of the blocks to be
- X included in this diff3_block. Create it. */
- X
- X tmpblock = using_to_diff3_block (using, last_using,
- X base_water_thread, high_water_thread,
- X last_diff);
- X
- X if (!tmpblock)
- X fatal ("internal: screwup in format of diff blocks");
- X
- X /* Put it on the list */
- X if (result)
- X result_last->next = tmpblock;
- X else
- X result = tmpblock;
- X result_last = tmpblock;
- X
- X /* Setup corresponding lines correctly */
- X last_diff = tmpblock;
- X }
- X return result;
- X}
- X
- X/*
- X * using_to_diff3_block:
- X * This routine takes two lists of blocks (from two separate diff
- X * threads) and puts them together into one diff3 block.
- X * It then returns a pointer to this diff3 block or 0 for failure.
- X *
- X * All arguments besides using are for the convenience of the routine;
- X * they could be derived from the using array.
- X * LAST_USING is a pair of pointers to the last blocks in the using
- X * structure.
- X * LOW_THREAD and HIGH_THREAD tell which threads contain the lowest
- X * and highest line numbers for File0.
- X * last_diff contains the last diff produced in the calling routine.
- X * This is used for lines mappings which would still be identical to
- X * the state that diff ended in.
- X *
- X * A distinction should be made in this routine between the two diffs
- X * that are part of a normal two diff block, and the three diffs that
- X * are part of a diff3_block.
- X */
- Xstruct diff3_block *
- Xusing_to_diff3_block (using, last_using, low_thread, high_thread, last_diff)
- X struct diff_block
- X *using[2],
- X *last_using[2];
- X int low_thread, high_thread;
- X struct diff3_block *last_diff;
- X{
- X int lowc, highc, low1, high1, low2, high2;
- X struct diff3_block *result;
- X struct diff_block *ptr;
- X int i;
- X int current0line;
- X
- X /* Find the range in file0 */
- X lowc = using[low_thread]->ranges[0][START];
- X highc = last_using[high_thread]->ranges[0][END];
- X
- X /* Find the ranges in the other files.
- X If using[x] is null, that means that the file to which that diff
- X refers is equivalent to file 0 over this range */
- X
- X if (using[0])
- X {
- X low1 = D_LOW_MAPLINE (using[0], FILE0, FILE1, lowc);
- X high1 = D_HIGH_MAPLINE (last_using[0], FILE0, FILE1, highc);
- X }
- X else
- X {
- X low1 = D_HIGH_MAPLINE (last_diff, FILEC, FILE1, lowc);
- X high1 = D_HIGH_MAPLINE (last_diff, FILEC, FILE1, highc);
- X }
- X
- X /*
- X * Note that in the following, we use file 1 relative to the diff,
- X * and file 2 relative to the corresponding lines struct.
- X */
- X if (using[1])
- X {
- X low2 = D_LOW_MAPLINE (using[1], FILE0, FILE1, lowc);
- X high2 = D_HIGH_MAPLINE (last_using[1], FILE0, FILE1, highc);
- X }
- X else
- X {
- X low2 = D_HIGH_MAPLINE (last_diff, FILEC, FILE2, lowc);
- X high2 = D_HIGH_MAPLINE (last_diff, FILEC, FILE2, highc);
- X }
- X
- X /* Create a block with the appropriate sizes */
- X result = create_diff3_block (lowc, highc, low1, high1, low2, high2);
- X
- X /* Copy over all of the information for File 0. Return with a zero
- X if any of the compares failed. */
- X for (ptr = using[0]; ptr; ptr = D_NEXT (ptr))
- X {
- X int result_offset = D_LOWLINE (ptr, FILE0) - lowc;
- X int copy_size
- X = D_HIGHLINE (ptr, FILE0) - D_LOWLINE (ptr, FILE0) + 1;
- X
- X if (!copy_stringlist (D_LINEARRAY (ptr, FILE0),
- X D_LENARRAY (ptr, FILE0),
- X D_LINEARRAY (result, FILEC) + result_offset,
- X D_LENARRAY (result, FILEC) + result_offset,
- X copy_size))
- X return 0;
- X }
- X
- X for (ptr = using[1]; ptr; ptr = D_NEXT (ptr))
- X {
- X int result_offset = D_LOWLINE (ptr, FILEC) - lowc;
- X int copy_size
- X = D_HIGHLINE (ptr, FILEC) - D_LOWLINE (ptr, FILEC) + 1;
- X
- X if (!copy_stringlist (D_LINEARRAY (ptr, FILE0),
- X D_LENARRAY (ptr, FILE0),
- X D_LINEARRAY (result, FILEC) + result_offset,
- X D_LENARRAY (result, FILEC) + result_offset,
- X copy_size))
- X return 0;
- X }
- X
- X /* Copy stuff for file 1. First deal with anything that might be
- X before the first diff. */
- X
- X for (i = 0;
- X i + low1 < (using[0] ? D_LOWLINE (using[0], FILE1) : high1 + 1);
- X i++)
- X {
- X D_RELNUM (result, FILE1, i) = D_RELNUM (result, FILEC, i);
- X D_RELLEN (result, FILE1, i) = D_RELLEN (result, FILEC, i);
- X }
- X
- X for (ptr = using[0]; ptr; ptr = D_NEXT (ptr))
- X {
- X int result_offset = D_LOWLINE (ptr, FILE1) - low1;
- X int copy_size
- X = D_HIGHLINE (ptr, FILE1) - D_LOWLINE (ptr, FILE1) + 1;
- X
- X if (!copy_stringlist (D_LINEARRAY (ptr, FILE1),
- X D_LENARRAY (ptr, FILE1),
- X D_LINEARRAY (result, FILE1) + result_offset,
- X D_LENARRAY (result, FILE1) + result_offset,
- X copy_size))
- X return 0;
- X
- X /* Catch the lines between here and the next diff */
- X current0line = D_HIGHLINE (ptr, FILE0) + 1 - lowc;
- X for (i = D_HIGHLINE (ptr, FILE1) + 1 - low1;
- X i < (D_NEXT (ptr) ?
- X D_LOWLINE (D_NEXT (ptr), FILE1) :
- X high1 + 1) - low1;
- X i++)
- X {
- X D_RELNUM (result, FILE1, i)
- X = D_RELNUM (result, FILEC, current0line);
- X D_RELLEN (result, FILE1, i)
- X = D_RELLEN (result, FILEC, current0line++);
- X }
- X }
- X
- X /* Copy stuff for file 2. First deal with anything that might be
- X before the first diff. */
- X
- X for (i = 0;
- X i + low2 < (using[1] ? D_LOWLINE (using[1], FILE1) : high2 + 1);
- X i++)
- X {
- X D_RELNUM (result, FILE2, i) = D_RELNUM (result, FILEC, i);
- X D_RELLEN (result, FILE2, i) = D_RELLEN (result, FILEC, i);
- X }
- X
- X for (ptr = using[1]; ptr; ptr = D_NEXT (ptr))
- X {
- X int result_offset = D_LOWLINE (ptr, FILE1) - low2;
- X int copy_size
- X = D_HIGHLINE (ptr, FILE1) - D_LOWLINE (ptr, FILE1) + 1;
- X
- X if (!copy_stringlist (D_LINEARRAY (ptr, FILE1),
- X D_LENARRAY (ptr, FILE1),
- X D_LINEARRAY (result, FILE2) + result_offset,
- X D_LENARRAY (result, FILE2) + result_offset,
- X copy_size))
- X return 0;
- X
- X /* Catch the lines between here and the next diff */
- X current0line = D_HIGHLINE (ptr, FILE0) + 1 - lowc;
- X for (i = D_HIGHLINE (ptr, FILE1) + 1 - low2;
- X i < (D_NEXT (ptr) ?
- X D_LOWLINE (D_NEXT (ptr), FILE1) :
- X high2 + 1) - low2;
- X i++)
- X {
- X D_RELNUM (result, FILE2, i)
- X = D_RELNUM (result, FILEC, current0line);
- X D_RELLEN (result, FILE2, i)
- X = D_RELLEN (result, FILEC, current0line++);
- X }
- X }
- X
- X /* Set correspond */
- X if (!using[0])
- X D3_TYPE (result) = DIFF_3RD;
- X else if (!using[1])
- X D3_TYPE (result) = DIFF_2ND;
- X else
- X {
- X int nl1
- X = D_HIGHLINE (result, FILE1) - D_LOWLINE (result, FILE1) + 1;
- X int nl2
- X = D_HIGHLINE (result, FILE2) - D_LOWLINE (result, FILE2) + 1;
- X
- X if (nl1 != nl2
- X || !compare_line_list (D_LINEARRAY (result, FILE1),
- X D_LENARRAY (result, FILE1),
- X D_LINEARRAY (result, FILE2),
- X D_LENARRAY (result, FILE2),
- X nl1))
- X D3_TYPE (result) = DIFF_ALL;
- X else
- X D3_TYPE (result) = DIFF_1ST;
- X }
- X
- X return result;
- X}
- X
- X/*
- X * This routine copies pointers from a list of strings to a different list
- X * of strings. If a spot in the second list is already filled, it
- X * makes sure that it is filled with the same string; if not it
- X * returns 0, the copy incomplete.
- X * Upon successful completion of the copy, it returns 1.
- X */
- Xint
- Xcopy_stringlist (fromptrs, fromlengths, toptrs, tolengths, copynum)
- X char *fromptrs[], *toptrs[];
- X int *fromlengths, *tolengths;
- X int copynum;
- X{
- X register char
- X **f = fromptrs,
- X **t = toptrs;
- X register int
- X *fl = fromlengths,
- X *tl = tolengths;
- X
- X while (copynum--)
- X {
- X if (*t)
- X { if (*fl != *tl || bcmp (*f, *t, *fl)) return 0; }
- X else
- X { *t = *f ; *tl = *fl; }
- X
- X t++; f++; tl++; fl++;
- X }
- X return 1;
- X}
- X
- X/*
- X * Create a diff3_block, with ranges as specified in the arguments.
- X * Allocate the arrays for the various pointers (and zero them) based
- X * on the arguments passed. Return the block as a result.
- X */
- Xstruct diff3_block *
- Xcreate_diff3_block (low0, high0, low1, high1, low2, high2)
- X register int low0, high0, low1, high1, low2, high2;
- X{
- X struct diff3_block *result = ALLOCATE (1, struct diff3_block);
- X int numlines;
- X
- X D3_TYPE (result) = ERROR;
- X D_NEXT (result) = 0;
- X
- X /* Assign ranges */
- X D_LOWLINE (result, FILE0) = low0;
- X D_HIGHLINE (result, FILE0) = high0;
- X D_LOWLINE (result, FILE1) = low1;
- X D_HIGHLINE (result, FILE1) = high1;
- X D_LOWLINE (result, FILE2) = low2;
- X D_HIGHLINE (result, FILE2) = high2;
- X
- X /* Allocate and zero space */
- X numlines = D_NUMLINES (result, FILE0);
- X if (numlines)
- X {
- X D_LINEARRAY (result, FILE0) = ALLOCATE (numlines, char *);
- X D_LENARRAY (result, FILE0) = ALLOCATE (numlines, int);
- X bzero (D_LINEARRAY (result, FILE0), (numlines * sizeof (char *)));
- X bzero (D_LENARRAY (result, FILE0), (numlines * sizeof (int)));
- X }
- X else
- X {
- X D_LINEARRAY (result, FILE0) = (char **) 0;
- X D_LENARRAY (result, FILE0) = (int *) 0;
- X }
- X
- X numlines = D_NUMLINES (result, FILE1);
- X if (numlines)
- X {
- X D_LINEARRAY (result, FILE1) = ALLOCATE (numlines, char *);
- X D_LENARRAY (result, FILE1) = ALLOCATE (numlines, int);
- X bzero (D_LINEARRAY (result, FILE1), (numlines * sizeof (char *)));
- X bzero (D_LENARRAY (result, FILE1), (numlines * sizeof (int)));
- X }
- X else
- X {
- X D_LINEARRAY (result, FILE1) = (char **) 0;
- X D_LENARRAY (result, FILE1) = (int *) 0;
- X }
- X
- X numlines = D_NUMLINES (result, FILE2);
- X if (numlines)
- X {
- X D_LINEARRAY (result, FILE2) = ALLOCATE (numlines, char *);
- X D_LENARRAY (result, FILE2) = ALLOCATE (numlines, int);
- X bzero (D_LINEARRAY (result, FILE2), (numlines * sizeof (char *)));
- X bzero (D_LENARRAY (result, FILE2), (numlines * sizeof (int)));
- X }
- X else
- X {
- X D_LINEARRAY (result, FILE2) = (char **) 0;
- X D_LENARRAY (result, FILE2) = (int *) 0;
- X }
- X
- X /* Return */
- X return result;
- X}
- X
- X/*
- X * Compare two lists of lines of text.
- X * Return 1 if they are equivalent, 0 if not.
- X */
- Xint
- Xcompare_line_list (list1, lengths1, list2, lengths2, nl)
- X char *list1[], *list2[];
- X int *lengths1, *lengths2;
- X int nl;
- X{
- X char
- X **l1 = list1,
- X **l2 = list2;
- X int
- X *lgths1 = lengths1,
- X *lgths2 = lengths2;
- X
- X while (nl--)
- X if (!*l1 || !*l2 || *lgths1 != *lgths2++
- X || bcmp (*l1++, *l2++, *lgths1++))
- X return 0;
- X return 1;
- X}
- X
- X/*
- X * Routines to input and parse two way diffs.
- X */
- X
- Xextern char **environ;
- X
- X#define DIFF_CHUNK_SIZE 10000
- X
- Xstruct diff_block *
- Xprocess_diff (filea, fileb)
- X char *filea, *fileb;
- X{
- X char *diff_contents;
- X char *diff_limit;
- X char *scan_diff;
- X enum diff_type dt;
- X int i;
- X struct diff_block *block_list, *block_list_end, *bptr;
- X
- X diff_limit = read_diff (filea, fileb, &diff_contents);
- X scan_diff = diff_contents;
- X bptr = block_list_end = block_list = (struct diff_block *) 0;
- X
- X while (scan_diff < diff_limit)
- X {
- X bptr = ALLOCATE (1, struct diff_block);
- X bptr->next = 0;
- X bptr->lines[0] = bptr->lines[1] = (char **) 0;
- X bptr->lengths[0] = bptr->lengths[1] = (int *) 0;
- X
- X dt = process_diff_control (&scan_diff, bptr);
- X if (dt == ERROR || *scan_diff != '\n')
- X {
- X fprintf (stderr, "%s: diff error: ", argv0);
- X do
- X {
- X putc (*scan_diff, stderr);
- X }
- X while (*scan_diff++ != '\n');
- X exit (2);
- X }
- X scan_diff++;
- X
- X /* Force appropriate ranges to be null, if necessary */
- X switch (dt)
- X {
- X case ADD:
- X bptr->ranges[0][0]++;
- X break;
- X case DELETE:
- X bptr->ranges[1][0]++;
- X break;
- X case CHANGE:
- X break;
- X default:
- X fatal ("internal: Bad diff type in process_diff");
- X break;
- X }
- X
- X /* Allocate space for the pointers for the lines from filea, and
- X parcel them out among these pointers */
- X if (dt != ADD)
- X {
- X bptr->lines[0] = ALLOCATE ((bptr->ranges[0][END]
- X - bptr->ranges[0][START] + 1),
- X char *);
- X bptr->lengths[0] = ALLOCATE ((bptr->ranges[0][END]
- X - bptr->ranges[0][START] + 1),
- X int);
- X for (i = 0; i <= (bptr->ranges[0][END]
- X - bptr->ranges[0][START]); i++)
- X scan_diff = scan_diff_line (scan_diff,
- X &(bptr->lines[0][i]),
- X &(bptr->lengths[0][i]),
- X diff_limit,
- X '<');
- X }
- X
- X /* Get past the separator for changes */
- X if (dt == CHANGE)
- X {
- X if (strncmp (scan_diff, "---\n", 4))
- X fatal ("Bad diff format: bad change separator");
- X scan_diff += 4;
- X }
- X
- X /* Allocate space for the pointers for the lines from fileb, and
- X parcel them out among these pointers */
- X if (dt != DELETE)
- X {
- X bptr->lines[1] = ALLOCATE ((bptr->ranges[1][END]
- X - bptr->ranges[1][START] + 1),
- X char *);
- X bptr->lengths[1] = ALLOCATE ((bptr->ranges[1][END]
- X - bptr->ranges[1][START] + 1),
- X int);
- X for (i = 0; i <= (bptr->ranges[1][END]
- X - bptr->ranges[1][START]); i++)
- X scan_diff = scan_diff_line (scan_diff,
- X &(bptr->lines[1][i]),
- X &(bptr->lengths[1][i]),
- X diff_limit,
- X '>');
- X }
- X
- X /* Place this block on the blocklist */
- X if (block_list_end)
- X block_list_end->next = bptr;
- X else
- X block_list = bptr;
- X
- X block_list_end = bptr;
- X
- X }
- X
- X return block_list;
- X}
- X
- X/*
- X * This routine will parse a normal format diff control string. It
- X * returns the type of the diff (ERROR if the format is bad). All of
- X * the other important information is filled into to the structure
- X * pointed to by db, and the string pointer (whose location is passed
- X * to this routine) is updated to point beyond the end of the string
- X * parsed. Note that only the ranges in the diff_block will be set by
- X * this routine.
- X *
- X * If some specific pair of numbers has been reduced to a single
- X * number, then both corresponding numbers in the diff block are set
- X * to that number. In general these numbers are interpetted as ranges
- X * inclusive, unless being used by the ADD or DELETE commands. It is
- X * assumed that these will be special cased in a superior routine.
- X */
- X
- Xenum diff_type
- Xprocess_diff_control (string, db)
- X char **string;
- X struct diff_block *db;
- X{
- X char *s = *string;
- X int holdnum;
- X enum diff_type type;
- X
- X/* These macros are defined here because they can use variables
- X defined in this function. Don't try this at home kids, we're
- X trained professionals!
- X
- X Also note that SKIPWHITE only recognizes tabs and spaces, and
- X that READNUM can only read positive, integral numbers */
- X
- X#define SKIPWHITE(s) { while (*s == ' ' || *s == '\t') s++; }
- X#define READNUM(s, num) \
- X { if (!isdigit (*s)) return ERROR; holdnum = 0; \
- X do { holdnum = (*s++ - '0' + holdnum * 10); } \
- X while (isdigit (*s)); (num) = holdnum; }
- X
- X /* Read first set of digits */
- X SKIPWHITE (s);
- X READNUM (s, db->ranges[0][START]);
- X
- X /* Was that the only digit? */
- X SKIPWHITE(s);
- X if (*s == ',')
- X {
- X /* Get the next digit */
- X s++;
- X READNUM (s, db->ranges[0][END]);
- X }
- X else
- X db->ranges[0][END] = db->ranges[0][START];
- X
- X /* Get the letter */
- X SKIPWHITE (s);
- X switch (*s)
- X {
- X case 'a':
- X type = ADD;
- X break;
- X case 'c':
- X type = CHANGE;
- X break;
- X case 'd':
- X type = DELETE;
- X break;
- X default:
- X return ERROR; /* Bad format */
- X }
- X s++; /* Past letter */
- X
- X /* Read second set of digits */
- X SKIPWHITE (s);
- X READNUM (s, db->ranges[1][START]);
- X
- X /* Was that the only digit? */
- X SKIPWHITE(s);
- X if (*s == ',')
- X {
- X /* Get the next digit */
- X s++;
- X READNUM (s, db->ranges[1][END]);
- X SKIPWHITE (s); /* To move to end */
- X }
- X else
- X db->ranges[1][END] = db->ranges[1][START];
- X
- X *string = s;
- X return type;
- X}
- X
- Xchar *
- Xread_diff (filea, fileb, output_placement)
- X char *filea, *fileb;
- X char **output_placement;
- X{
- X char *argv[6];
- X char **ap;
- X int fds[2];
- X char *diff_result;
- X int current_chunk_size;
- X int bytes;
- X int total;
- X int pid, w;
- X int wstatus;
- X
- X ap = argv;
- X *ap++ = diff_program;
- X if (always_text)
- X *ap++ = "-a";
- X *ap++ = "--";
- X *ap++ = filea;
- X *ap++ = fileb;
- X *ap = (char *) 0;
- X
- X if (pipe (fds) < 0)
- X perror_with_exit ("Pipe failed");
- X
- X pid = vfork ();
- X if (pid == 0)
- X {
- X /* Child */
- X close (fds[0]);
- X if (fds[1] != fileno (stdout))
- X {
- X dup2 (fds[1], fileno (stdout));
- X close (fds[1]);
- X }
- X execve (diff_program, argv, environ);
- X /* Avoid stdio, because the parent process's buffers are inherited. */
- X write (fileno (stderr), diff_program, strlen (diff_program));
- X write (fileno (stderr), ": not found\n", 12);
- X _exit (2);
- X }
- X
- X if (pid == -1)
- X perror_with_exit ("Fork failed");
- X
- X close (fds[1]); /* Prevent erroneous lack of EOF */
- X current_chunk_size = DIFF_CHUNK_SIZE;
- X diff_result = (char *) xmalloc (current_chunk_size);
- X total = 0;
- X do {
- X bytes = myread (fds[0],
- X diff_result + total,
- X current_chunk_size - total);
- X total += bytes;
- X if (total == current_chunk_size)
- X diff_result = (char *) xrealloc (diff_result, (current_chunk_size *= 2));
- X } while (bytes);
- X
- X if (total != 0 && diff_result[total-1] != '\n')
- X fatal ("bad diff format; incomplete last line");
- X
- X *output_placement = diff_result;
- X
- X do
- X if ((w = wait (&wstatus)) == -1)
- X perror_with_exit ("Wait failed");
- X while (w != pid);
- X
- X if (! (WIFEXITED (wstatus) && WEXITSTATUS (wstatus) < 2))
- X fatal ("Subsidiary diff failed");
- X
- X return diff_result + total;
- X}
- X
- X
- X/*
- X * Scan a regular diff line (consisting of > or <, followed by a
- X * space, followed by text (including nulls) up to a newline.
- X *
- X * This next routine began life as a macro and many parameters in it
- X * are used as call-by-reference values.
- X */
- Xchar *
- Xscan_diff_line (scan_ptr, set_start, set_length, limit, firstchar)
- X char *scan_ptr, **set_start;
- X int *set_length;
- X char *limit;
- X char firstchar;
- X{
- X char *line_ptr;
- X
- X if (!(scan_ptr[0] == (firstchar)
- X && scan_ptr[1] == ' '))
- X fatal ("Bad diff format; incorrect leading line chars");
- X
- X *set_start = line_ptr = scan_ptr + 2;
- X while (*line_ptr++ != '\n')
- X ;
- X
- X /* Include newline if the original line ended in a newline,
- X or if an edit script is being generated.
- X Copy any missing newline message to stderr if an edit script is being
- X generated, because edit scripts cannot handle missing newlines.
- X Return the beginning of the next line. */
- X *set_length = line_ptr - *set_start;
- X if (line_ptr < limit && *line_ptr == '\\')
- X {
- X if (edscript)
- X fprintf (stderr, "%s:", argv0);
- X else
- X --*set_length;
- X line_ptr++;
- X do
- X {
- X if (edscript)
- X putc (*line_ptr, stderr);
- X }
- X while (*line_ptr++ != '\n');
- X }
- X
- X return line_ptr;
- X}
- X
- X/*
- X * This routine outputs a three way diff passed as a list of
- X * diff3_block's.
- X * The argument MAPPING is indexed by external file number (in the
- X * argument list) and contains the internal file number (from the
- X * diff passed). This is important because the user expects his
- X * outputs in terms of the argument list number, and the diff passed
- X * may have been done slightly differently (if the first argument in
- X * the argument list was the standard input, for example).
- X * REV_MAPPING is the inverse of MAPPING.
- X */
- Xvoid
- Xoutput_diff3 (outputfile, diff, mapping, rev_mapping)
- X FILE *outputfile;
- X struct diff3_block *diff;
- X int mapping[3], rev_mapping[3];
- X{
- X int i;
- X int oddoneout;
- X char *cp;
- X struct diff3_block *ptr;
- X int line;
- X int length;
- X int dontprint;
- X static int skew_increment[3] = { 2, 3, 1 }; /* 0==>2==>1==>3 */
- X
- X for (ptr = diff; ptr; ptr = D_NEXT (ptr))
- X {
- X char x[2];
- X
- X switch (ptr->correspond)
- X {
- X case DIFF_ALL:
- X x[0] = '\0';
- X dontprint = 3; /* Print them all */
- X oddoneout = 3; /* Nobody's odder than anyone else */
- X break;
- X case DIFF_1ST:
- X case DIFF_2ND:
- X case DIFF_3RD:
- X oddoneout = rev_mapping[(int) ptr->correspond - (int) DIFF_1ST];
- X
- X x[0] = oddoneout + '1';
- X x[1] = '\0';
- X dontprint = oddoneout==0;
- X break;
- X default:
- X fatal ("internal: Bad diff type passed to output");
- X }
- X fprintf (outputfile, "====%s\n", x);
- X
- X /* Go 0, 2, 1 if the first and third outputs are equivalent. */
- X for (i = 0; i < 3;
- X i = (oddoneout == 1 ? skew_increment[i] : i + 1))
- X {
- X int realfile = mapping[i];
- X int
- X lowt = D_LOWLINE (ptr, realfile),
- X hight = D_HIGHLINE (ptr, realfile);
- X
- X fprintf (outputfile, "%d:", i + 1);
- X switch (lowt - hight)
- X {
- X case 1:
- X fprintf (outputfile, "%da\n", lowt - 1);
- X break;
- X case 0:
- X fprintf (outputfile, "%dc\n", lowt);
- X break;
- X default:
- X fprintf (outputfile, "%d,%dc\n", lowt, hight);
- X break;
- X }
- X
- X if (i == dontprint) continue;
- X
- X for (line = 0; line < hight - lowt + 1; line++)
- X {
- X fprintf (outputfile, " ");
- X cp = D_RELNUM (ptr, realfile, line);
- X length = D_RELLEN (ptr, realfile, line);
- X fwrite (cp, sizeof (char), length, outputfile);
- X }
- X if (line != 0 && cp[length - 1] != '\n')
- X fprintf (outputfile, "\n\\ No newline at end of file\n");
- X }
- X }
- X}
- X
- X/*
- X * This routine outputs a diff3 set of blocks as an ed script. This
- X * script applies the changes between file's 2 & 3 to file 1. It
- X * takes the precise format of the ed script to be output from global
- X * variables set during options processing. Note that it does
- X * destructive things to the set of diff3 blocks it is passed; it
- X * reverses their order (this gets around the problems involved with
- X * changing line numbers in an ed script).
- X *
- X * Note that this routine has the same problem of mapping as the last
- X * one did; the variable MAPPING maps from file number according to
- X * the argument list to file number according to the diff passed. All
- X * files listed below are in terms of the argument list.
- X * REV_MAPPING is the inverse of MAPPING.
- X *
- X * The arguments FILE0, FILE1 and FILE2 are the strings to print
- X * as the names of the three files. These may be the actual names,
- X * or may be the arguments specified with -L.
- X *
- X * Returns 1 if overlaps were found.
- X */
- X
- Xint
- Xoutput_diff3_edscript (outputfile, diff, mapping, rev_mapping,
- X file0, file1, file2)
- X FILE *outputfile;
- X struct diff3_block *diff;
- X int mapping[3], rev_mapping[3];
- X char *file0, *file1, *file2;
- X{
- X int i;
- X int leading_dot;
- X int overlaps_found = 0;
- X struct diff3_block *newblock, *thisblock;
- X
- X leading_dot = 0;
- X
- X newblock = reverse_diff3_blocklist (diff);
- X
- X for (thisblock = newblock; thisblock; thisblock = thisblock->next)
- X {
- X /* Must do mapping correctly. */
- X enum diff_type type
- X = ((thisblock->correspond == DIFF_ALL) ?
- X DIFF_ALL :
- X ((enum diff_type)
- X (((int) DIFF_1ST)
- X + rev_mapping[(int) thisblock->correspond - (int) DIFF_1ST])));
- X
- X /* If we aren't supposed to do this output block, skip it */
- X if (type == DIFF_2ND || type == DIFF_1ST
- X || (type == DIFF_3RD && dont_write_simple)
- X || (type == DIFF_ALL && dont_write_overlap))
- X continue;
- X
- X if (flagging && type == DIFF_ALL)
- X /* Do special flagging */
- X {
- X
- X /* Put in lines from FILE2 with bracket */
- X fprintf (outputfile, "%da\n",
- X D_HIGHLINE (thisblock, mapping[FILE0]));
- X fprintf (outputfile, "=======\n");
- X for (i = 0;
- X i < D_NUMLINES (thisblock, mapping[FILE2]);
- X i++)
- X {
- X if (D_RELNUM (thisblock, mapping[FILE2], i)[0] == '.')
- X { leading_dot = 1; fprintf(outputfile, "."); }
- X fwrite (D_RELNUM (thisblock, mapping[FILE2], i), sizeof (char),
- X D_RELLEN (thisblock, mapping[FILE2], i), outputfile);
- X }
- X fprintf (outputfile, ">>>>>>> %s\n.\n", file2);
- X overlaps_found = 1;
- X
- X /* Add in code to take care of leading dots, if necessary. */
- X if (leading_dot)
- X {
- X fprintf (outputfile, "%d,%ds/^\\.\\./\\./\n",
- X D_HIGHLINE (thisblock, mapping[FILE0]) + 1,
- X (D_HIGHLINE (thisblock, mapping[FILE0])
- X + D_NUMLINES (thisblock, mapping[FILE2])));
- X leading_dot = 0;
- X }
- X
- X /* Put in code to do initial bracket of lines from FILE0 */
- X fprintf (outputfile, "%da\n<<<<<<< %s\n.\n",
- X D_LOWLINE (thisblock, mapping[FILE0]) - 1,
- X file0);
- X }
- X else if (D_NUMLINES (thisblock, mapping[FILE2]) == 0)
- X /* Write out a delete */
- X {
- X if (D_NUMLINES (thisblock, mapping[FILE0]) == 1)
- X fprintf (outputfile, "%dd\n",
- X D_LOWLINE (thisblock, mapping[FILE0]));
- X else
- X fprintf (outputfile, "%d,%dd\n",
- X D_LOWLINE (thisblock, mapping[FILE0]),
- X D_HIGHLINE (thisblock, mapping[FILE0]));
- X }
- X else
- X /* Write out an add or change */
- X {
- X switch (D_NUMLINES (thisblock, mapping[FILE0]))
- X {
- X case 0:
- X fprintf (outputfile, "%da\n",
- X D_HIGHLINE (thisblock, mapping[FILE0]));
- X break;
- X case 1:
- X fprintf (outputfile, "%dc\n",
- X D_HIGHLINE (thisblock, mapping[FILE0]));
- X break;
- X default:
- X fprintf (outputfile, "%d,%dc\n",
- X D_LOWLINE (thisblock, mapping[FILE0]),
- X D_HIGHLINE (thisblock, mapping[FILE0]));
- X break;
- X }
- X for (i = 0;
- X i < D_NUMLINES (thisblock, mapping[FILE2]);
- X i++)
- X {
- X if (D_RELNUM (thisblock, mapping[FILE2], i)[0] == '.')
- X { leading_dot = 1; fprintf (outputfile, "."); }
- X fwrite (D_RELNUM (thisblock, mapping[FILE2], i), sizeof (char),
- X D_RELLEN (thisblock, mapping[FILE2], i), outputfile);
- X }
- X fprintf (outputfile, ".\n");
- X
- X /* Add in code to take care of leading dots, if necessary. */
- X if (leading_dot)
- X {
- X fprintf (outputfile, "%d,%ds/^\\.\\./\\./\n",
- X D_HIGHLINE (thisblock, mapping[FILE0]) + 1,
- X (D_HIGHLINE (thisblock, mapping[FILE0])
- X + D_NUMLINES (thisblock, mapping[FILE2])));
- X leading_dot = 0;
- X }
- X }
- X }
- X if (finalwrite) fprintf (outputfile, "w\nq\n");
- X return overlaps_found;
- X}
- X
- X/*
- X * Read from COMMONFILE and output to OUTPUTFILE a set of diff3_ blocks DIFF
- X * as a merged file. This acts like 'ed file0 <[output_diff3_edscript]',
- X * except that it works even for binary data or incomplete lines.
- X *
- X * As before, MAPPING maps from arg list file number to diff file number,
- X * REV_MAPPING is its inverse,
- X * and FILE0, FILE1, and FILE2 are the names of the files.
- X *
- X * Returns 1 if overlaps were found.
- X */
- X
- Xint
- Xoutput_diff3_merge (commonfile, outputfile, diff, mapping, rev_mapping,
- X file0, file1, file2)
- X FILE *commonfile, *outputfile;
- X struct diff3_block *diff;
- X int mapping[3], rev_mapping[3];
- X char *file0, *file1, *file2;
- X{
- X int c, i;
- X int overlaps_found = 0;
- X struct diff3_block *b;
- X int linesread = 0;
- X
- X for (b = diff; b; b = b->next)
- X {
- X /* Must do mapping correctly */
- X enum diff_type type
- X = ((b->correspond == DIFF_ALL) ?
- X DIFF_ALL :
- X ((enum diff_type)
- X (((int) DIFF_1ST)
- X + rev_mapping[(int) b->correspond - (int) DIFF_1ST])));
- X
- X /* If we aren't supposed to do this output block, skip it. */
- X if (type == DIFF_2ND || type == DIFF_1ST
- X || (type == DIFF_3RD && dont_write_simple)
- X || (type == DIFF_ALL && dont_write_overlap))
- X continue;
- X
- X /* Copy I lines from common file. */
- X i = D_LOWLINE (b, FILE0) - linesread - 1;
- X linesread += i;
- X while (0 <= --i)
- X {
- X while ((c = getc(commonfile)) != '\n')
- X {
- X if (c == EOF)
- X fatal ("input file shrank");
- X putc (c, outputfile);
- X }
- X putc (c, outputfile);
- X }
- X
- X if (flagging && type == DIFF_ALL)
- X /* Do special flagging. */
- X {
- X /* Put in lines from FILE0 with bracket. */
- X fprintf (outputfile, "<<<<<<< %s\n", file0);
- X for (i = 0;
- X i < D_NUMLINES (b, mapping[FILE0]);
- X i++)
- X fwrite (D_RELNUM (b, mapping[FILE0], i), sizeof (char),
- X D_RELLEN (b, mapping[FILE0], i), outputfile);
- X fprintf (outputfile, "=======\n");
- X overlaps_found = 1;
- X }
- X
- X /* Put in lines from FILE2. */
- X for (i = 0;
- X i < D_NUMLINES (b, mapping[FILE2]);
- X i++)
- X fwrite (D_RELNUM (b, mapping[FILE2], i), sizeof (char),
- X D_RELLEN (b, mapping[FILE2], i), outputfile);
- X
- X if (flagging && type == DIFF_ALL)
- X fprintf (outputfile, ">>>>>>> %s\n", file2);
- X
- X /* Skip I lines in common file. */
- X i = D_NUMLINES (b, FILE0);
- X linesread += i;
- X while (0 <= --i)
- X while ((c = getc(commonfile)) != '\n')
- X if (c == EOF)
- X {
- X if (i || b->next)
- X fatal ("input file shrank");
- X return overlaps_found;
- X }
- X }
- X /* Copy rest of common file. */
- X while ((c = getc (commonfile)) != EOF)
- X putc (c, outputfile);
- X return overlaps_found;
- X}
- X
- X/*
- X * Reverse the order of the list of diff3 blocks.
- X */
- Xstruct diff3_block *
- Xreverse_diff3_blocklist (diff)
- X struct diff3_block *diff;
- X{
- X register struct diff3_block *tmp, *next, *prev;
- X
- X for (tmp = diff, prev = (struct diff3_block *) 0;
- X tmp; tmp = next)
- X {
- X next = tmp->next;
- X tmp->next = prev;
- X prev = tmp;
- X }
- X
- X return prev;
- X}
- X
- Xint
- Xmyread (fd, ptr, size)
- X int fd, size;
- X char *ptr;
- X{
- X int result = read (fd, ptr, size);
- X if (result < 0)
- X perror_with_exit ("Read failed");
- X return result;
- X}
- X
- XVOID *
- Xxmalloc (size)
- X int size;
- X{
- X VOID *result = (VOID *) malloc (size ? size : 1);
- X if (!result)
- X fatal ("Malloc failed");
- X return result;
- X}
- X
- XVOID *
- Xxrealloc (ptr, size)
- X VOID *ptr;
- X int size;
- X{
- X VOID *result = (VOID *) realloc (ptr, size ? size : 1);
- X if (!result)
- X fatal ("Malloc failed");
- X return result;
- X}
- X
- Xfatal (string)
- X char *string;
- X{
- X fprintf (stderr, "%s: %s\n", argv0, string);
- X exit (2);
- X}
- X
- Xperror_with_exit (string)
- X char *string;
- X{
- X perror (string);
- X exit (2);
- X}
- END_OF_FILE
- if test 46642 -ne `wc -c <'diff3.c'`; then
- echo shar: \"'diff3.c'\" unpacked with wrong size!
- fi
- # end of 'diff3.c'
- fi
- echo shar: End of archive 8 \(of 8\).
- cp /dev/null ark8isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 8 archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-
- exit 0 # Just in case...
-